package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartAsyncService;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private CartAsyncService cartAsyncService;

    @Override
    public void addToCart(Long skuId, String userId, Integer skuNum) {
        /*
            1. 添加购物车之前,先查看购物车中是否已有该商品
            2. 将数据同步到redis
         */
        String cartKey = getCartKey(userId);
        //判断缓存中是否有数据
        if (!redisTemplate.hasKey(cartKey)) {
            // 加载数据库放入缓存
            loadCartCache(userId);
        }
        // 查询缓存hget(key,field)
        CartInfo cartInfoExist = (CartInfo) redisTemplate.boundHashOps(cartKey).get(skuId.toString());
        if (cartInfoExist != null) {
            cartInfoExist.setSkuNum(cartInfoExist.getSkuNum() + skuNum);
            cartInfoExist.setCartPrice(productFeignClient.getSkuPrice(skuId));
            cartInfoExist.setUpdateTime(new Timestamp(new Date().getTime()));
            cartInfoExist.setIsChecked(1);
            cartAsyncService.updateCartInfo(cartInfoExist);
        } else {
            //第一次添加购物车
            CartInfo cartInfo = new CartInfo();
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setCreateTime(new Timestamp(new Date().getTime()));
            cartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
            cartAsyncService.saveCartInfo(cartInfo);
            cartInfoExist = cartInfo;

        }
        redisTemplate.boundHashOps(cartKey).put(skuId.toString(), cartInfoExist);
        setCartKeyExpire(cartKey);
    }

    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
        //未登录
        if (StringUtils.isEmpty(userId)) {
            cartInfoList = getCartList(userTempId);
            return cartInfoList;
        }
         /*
             1. 准备合并购物车
             2. 获取未登录的购物车数据
             3. 如果未登录购物车中有数据，则进行合并 合并的条件：skuId 相同 则数量相加，合并完成之后，删除未登录的数据！
             4. 如果未登录购物车没有数据，则直接显示已登录的数据
          */

        //已登录
        else {
            List<CartInfo> cartInfos = getCartList(userTempId);
            if (!CollectionUtils.isEmpty(cartInfos)) {
                cartInfoList = mergeToCartList(cartInfos, userId);
                delectCartList(userTempId);
            }
            if (CollectionUtils.isEmpty(cartInfos) || StringUtils.isEmpty(userTempId)) {
                cartInfoList = getCartList(userId);
            }

            return cartInfoList;
        }
    }


    /**
     * 更改选中状态
     * @param userId
     * @param isChecked
     * @param skuId
     */
    @Override
    public void checkCart(String userId, Integer isChecked, Long skuId) {
        //更改数据库
        cartAsyncService.checkCart(userId,isChecked,skuId);
        //更改缓存
        String cartKey = getCartKey(userId);
        BoundHashOperations<String,String,CartInfo> ops = redisTemplate.boundHashOps(cartKey);
        if (ops.hasKey(skuId.toString())){
            CartInfo cartInfoUpd = ops.get(skuId.toString());
            cartInfoUpd.setIsChecked(isChecked);
            ops.put(skuId.toString(),cartInfoUpd);
            setCartKeyExpire(cartKey);
        }
    }

    @Override
    public void deleteCartInfo(Long userId, String skuId) {
        String cartKey = getCartKey(userId.toString());
        cartAsyncService.deleteCartInfo(userId,skuId);
        BoundHashOperations<String,String,CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        if (hashOps.hasKey(skuId.toString())){
            hashOps.delete(skuId.toString());
        }
    }

    /**
     * 根据用户id 查询购物车列表
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
        //定义key
        String cartKey = this.getCartKey(userId);
        List<CartInfo> cartCacheInfoList = redisTemplate.opsForHash().values(cartKey);
        if (null!= cartCacheInfoList && cartCacheInfoList.size()>0){
            for (CartInfo cartInfo : cartCacheInfoList) {
                if (cartInfo.getIsChecked().intValue()==1){
                    cartInfoList.add(cartInfo);
                }
            }
        }
        return cartInfoList;
    }

    /**
     * 合并完成之后，删除未登录的数据！
     *
     * @param userTempId
     */
    private void delectCartList(String userTempId) {
        String cartKey = getCartKey(userTempId);
        cartAsyncService.delectCartList(userTempId);
        if (redisTemplate.hasKey(cartKey))
            redisTemplate.delete(cartKey);
    }

    /**
     * 进行合并 合并的条件：skuId 相同 则数量相加
     *
     * @param noLoginList
     * @param userId
     * @return
     */
    private List<CartInfo> mergeToCartList(List<CartInfo> noLoginList, String userId) {
        List<CartInfo> loginList = getCartList(userId);
        Map<Long, CartInfo> longCartInfoMap = loginList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));

        for (CartInfo cartInfo : noLoginList) {
            Long skuId = cartInfo.getSkuId();
            if (longCartInfoMap.containsKey(skuId)) {
                CartInfo loginCartInfo = longCartInfoMap.get(skuId);
                loginCartInfo.setSkuNum(loginCartInfo.getSkuNum() + cartInfo.getSkuNum());
                loginCartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
                if (cartInfo.getIsChecked() == 1) loginCartInfo.setIsChecked(1);
                cartInfoMapper.update(loginCartInfo, new QueryWrapper<CartInfo>().eq("sku_id", cartInfo.getSkuId()).eq("user_id", userId));
            }else {
                //已登录购物车无此skuid
                cartInfo.setUserId(userId);
                cartInfo.setCreateTime(new Timestamp(new Date().getTime()));
                cartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
                cartInfoMapper.insert(cartInfo);
            }
        }
        return loadCartCache(userId);
    }

    /**
     * 根据用户获取购物车
     *
     * @param userId
     * @return
     */
    public List<CartInfo> getCartList(String userId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
        if (StringUtils.isEmpty(userId)) {

            return cartInfoList;
        }
        /*
    1.  根据用户Id 查询 {先查询缓存，缓存没有，再查询数据库}
     */
        // 定义key user:userId:cart
        String cartKey = this.getCartKey(userId);
        // 获取数据
        cartInfoList = redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            // 购物车列表显示有顺序：按照商品的更新时间 降序
            cartInfoList.sort((o1, o2) -> DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND));
            return cartInfoList;
        } else {
            // 缓存中没有数据！
            cartInfoList = loadCartCache(userId);
            return cartInfoList;
        }
    }

    /**
     * 通过用户id查询购物车并放入缓存
     *
     * @param userId
     * @return
     */
    public List<CartInfo> loadCartCache(String userId) {
        QueryWrapper queryWrapper = new QueryWrapper<CartInfo>();
        queryWrapper.eq("user_id", userId);
        List<CartInfo> cartInfoList = cartInfoMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(cartInfoList)) {
            return cartInfoList;
        }
        // 将数据库中的数据查询并放入缓存
        HashMap<String, CartInfo> map = new HashMap<>();
        for (CartInfo cartInfo : cartInfoList) {
            BigDecimal skuPrice = productFeignClient.getSkuPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(skuPrice);
            map.put(cartInfo.getSkuId().toString(), cartInfo);
        }

        // 定义key user:userId:cart
        String cartKey = this.getCartKey(userId);
        redisTemplate.opsForHash().putAll(cartKey, map);
        // 设置过期时间
        this.setCartKeyExpire(cartKey);
        return cartInfoList;

    }


    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }


    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }
}
